package albero;

import asd.TestObject;
import asd.graphics.GObject;
import asd.graphics.GStyle;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 * Classe che permette di manipolare l'oggetto albero.
 * Permette la stmpa testuale dell'albero e la creazione di un albero grafico.
 * @author Giovanni Cammarata
 * @param <E> 
 */
public class TreeUtil<E> {
	
	public void printInOrder(BTree<E> T){
		printInOrder((BNode<E>) T.root());
	}
	
	private void printInOrder(BNode<E> v){
		if (v.getLeft() != null)
			printInOrder(v.getLeft());
		System.out.print(v.getElement() + " ");
		if (v.getRight() != null)
			printInOrder(v.getRight());
	}
	
	public void printPreOrder(Tree<E> T){
		printPreOrder(T.root());
	}
	
	private void printPreOrder(Node<E> v){
		if (v.getParent() == null)
			System.out.print(v.getElement());
		else
			System.out.print(" " + v.getElement());
		for(Node<E> w: v.getChildren())
			printPreOrder(w);
		if (v.getParent() == null)
			System.out.println();
	}
	
	public Iterable<Node<E>> visitPostOrder(Tree<E> T){
		return visitPostOrder(T.root(), new ArrayList<Node<E>>());
	}
	
	private Iterable<Node<E>> visitPostOrder(Node<E> v, ArrayList<Node<E>> l){
		for(Node<E> w: v.getChildren())
			l = (ArrayList<Node<E>>) visitPostOrder(w,l);
		l.add(v);
		return l;
	}
	
	public int depth(Tree<E> T, Node<E> v){
		if (T.isRoot(v))
			return 0;
		return 1 + depth(T, v.getParent());
	}
	
	public int height(Tree<E> T){
		return height(T, T.root());
	}
	
	private int height(Tree<E> T, Node<E> v){
		if (T.isExternal(v))
			return 0;
		int h = 0;
		for(Node<E> w : T.children(v))
			h = Math.max(h, height(T, w));
		return 1 + h;
	}
	
    public void stampa(Tree<E> tree) {
        stampa(tree.root(), 0);
    }

    private void stampa(Node<E> v, int level) {
        if (v == null) return;
        for (int i = 0; i < level - 1; i++) {
            System.out.print("   ");
        }
        if (level > 0)
            System.out.print(" |--  ");
        System.out.println(v.getElement());
        for (Node<E> children : v.getChildren()) {
            stampa(children, level + 1);
        }
    }
    
    public void stampaNodi(Tree<E> tree) {
        stampaNodi(tree.root(), 0);
    }

    private void stampaNodi(Node<E> v, int level) {
        if (v == null) return;
        for (int i = 0; i < level - 1; i++) {
            System.out.print("   ");
        }
        if (level > 0)
            System.out.print(" |--  ");
        System.out.println(v.getElement().toString());
        for (Node<E> children : v.getChildren()) {
            stampaNodi(children, level + 1);
        }
    }
    
    public JTree buildJTree(Tree<E> tree) {
        JTree jtree = null;
        
        //aggiungo la radice
        Nodo root = (Nodo) tree.root().getElement();
        DefaultMutableTreeNode parent = new DefaultMutableTreeNode(root.toString(), true);
        
        addNodeJTree(tree.root(),parent, jtree,4);
        
        jtree = new JTree(parent);
        return jtree;
    }
    
    public void addNodeJTree(Node<E> v,DefaultMutableTreeNode nodo, JTree jtree, int level) {
        if (v == null) return;
        
          DefaultMutableTreeNode child;
        child = new DefaultMutableTreeNode(v.getElement().toString());
        
        nodo.add(child);
        
        for (Node<E> children : v.getChildren()) {
            addNodeJTree(children, child,jtree, level + 1);
        }
    }
    
    
    /**
     * Il metodo permette di disegnare graficamente l'albero,
     * ovvero la rappresentazione dell'albero sintattico decorato.
     * @param tree Struttura dati albero.
     * @param root radice dell'albero alal quale aggiunge i nodi.
     */
    public void disegnaAlbero(Tree<E> tree,GObject root) {
        disegnaAlbero(tree.root(), 0, root,650,255,255,255);
    }

    private void disegnaAlbero(Node<E> v, int level,GObject root, int x,int rgb1,int rgb2,int rgb3) {
        if (v == null) return;
        
        int numerofigli=v.getChildren().size();
        
        GObject child = new TestObject (v.getElement().toString(), root, x, 50.0+180*level);
        GStyle style = new GStyle();
        style.setBackgroundColor (new Color (rgb1, rgb2, rgb3));
        child.setStyle(style);
        //System.out.println(v.getElement().toString() +" POSIZIONE"+x);
        child.setParent_(root);
        
        if(v.getChildren().size()>0) {
            double larghezza = 900/numerofigli;
            int i=1;
            Iterator it = v.getChildren().iterator();
            int rand1 = (int)(Math.random() * 255);
            int rand2 = (int)(Math.random() * 255);
            int rand3 = (int)(Math.random() * 255);
            while(it.hasNext()) {
                Node<E> children = (Node<E>) it.next();
                disegnaAlbero(children, level + 1,child,(int)((larghezza-70*level)*i),rand1,rand2,rand3);
                i++;
            }
        }
        
    }

}
